// C++入门

// 看可不可以把作用域里面的函数用typedef重命名
// 答案:不可，因为它不是类型
#include <iostream>

using namespace std;

//namespace tj
//{
//	int rand;
//	int Add(int a, int b)
//	{
//		cout << "tj::Add" << endl;
//		return a + b;
//	}
//}
//
////typedef tj::Add Add;
////typedef tj::rand Add;
//
//int Add(int a, int b)
//{
//	cout << "全局Add" << endl;
//}
//
//void test()
//{
//	Add(1, 1);
//}
//
//using tj::Add;
//
//int main()
//{
//	Add(1, 1);
//	test();
//	return 0;
//}

//// 看引用初始化为另一个变量的别名是什么意思
//// 引用实际上是一个指针常量（注意：指针常量不是常量），int* const p
//// 结果：地址相同
//// 理解：int& x = b = a;
//// int* const x = int* const b = a;
//int main()
//{
//	int a = 0;
//	int& b = a;
//	int& x = b;/**/
//
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &x << endl;
//	return 0;
//}


//// 看返回引用的不同报错：
//// 1、返回局部变量的引用
//// 2、返回传入的参数的引用
//
//// 结果：warning C4172: 返回局部变量或临时变量的地址: b
//// 说明：只有返回  局部变量  的引用时，才会报错，其实返回局部变量的引用也就是野指针
//
//int& test1(int& a)
//{
//	return a;
//}
//
//int& test2(int& a)
//{
//	int b = 1;
//	return b;
//}
//
//int main()
//{
//	int a = 1;
//	test1(a);
//	test2(a);
//	return 0;
//}


//// 测试返回值不是void时，函数可不可以放在等号左边
//// 结果：
//// int&:可以
//// int:不可以 ----> 临时变量具有常性，不可修改
//
//int& test1(int& a)
//{
//	return a;
//}
//
//int test2(int& a)
//{
//	int b = 1;
//	return b;
//}
//
//int main()
//{
//	int a = 1;
//	test1(a) = 1;
//	//test2(a) = 1;
//	return 0;
//}


//// 看是否可以看见底层引用的本质
//// 结果：看不见
//// 但是引用本身是一个指针常量，int* const p，指向不可以改变，值可以改变
//
//int main()
//{
//	int a = 1;
//	int& b = a;
//
//	return 0;
//}



//// 这样子会在auto x : arr那里报错
///*
//当您声明一个函数参数为int arr[]时，实际上它会被编译器视为int* arr，
//即一个指向int的指针。编译器不会记住数组的大小，因为它只看到了一个指针。
//因此，当您在函数内部尝试使用基于范围的for循环时，编译器无法确定数组的大小，因此无法知道应该在何时停止循环。
//*/
//
//void Print(int arr[])
//// void Print(int* arr)
//{
//	for (auto x : arr)
//		cout << x << " ";
//	cout << endl;
//}
//
//int main()
//{
//	int arr[] = { 1, 2, 3, 4, 5 };
//	test1(arr);
//
//	return 0;
//}


//// 测试NULL在C++中的底层实现和在C中的底层实现（结合Test.c文件测试）
//
//// C++
///*
//#ifndef NULL
//	#ifdef __cplusplus
//		#define NULL 0
//*/
//
//// C
///*
//#else
//		#define NULL ((void *)0)
//	#endif
//#endif
//*/
//
//// 要想在C++中使用之前的NULL，就要么写nullptr，要么(void*)NULL
//
//int main()
//{
//	NULL;
//	(void*)NULL;
//	return 0;
//}



//// 验证两个this指针一不一样
//
//// 同一个对象，一样
//
//class Date
//{
//public:
//	void Init(int year, int month, int day)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//
//		cout << this << endl;
//		Print();
//	}
//	void Print()
//	{
//		cout << this << endl;
//	}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//}; 
//
//
//int main()
//{
//	Date d1;
//	d1.Init(2024, 7, 10);
//	return 0;
//}


// 坑题
// 不会崩溃，因为调用成员函数和对象无关，并没有进行解引用，汇编代码中函数传的地址也是函数的地址，和对象无关
//
//class A
//{
//public:
//	void Print()
//	{
//		cout << "Print()" << endl;
//	}
//
//// private:
//	int _a;
//};
//
//
//int main()
//{
//	A* p = nullptr;
//	p->Print();// 看汇编代码
//
//	p->_a;// 不会崩溃，因为没有对其修改和访问，在底层，编译器没有生成相关指令（可以看汇编代码），但是这和编译器有关（测试结果：linux下这个也不会崩溃）
//	return 0;
//}


//// 看struct会不会有构造函数
//// 有
//
//struct A
//{
//public:
//    A()
//    {
//        Print();
//    }
//
//    void Print()
//    {
//        cout << "Print()" << endl;
//    }
//
//    // private:
//    int _a;
//};
//
//
//int main()
//{
//    A a;
//    return 0;
//}



//// 看可不可以在类的声明给初始值
//// 可以，c++11支持的
//
//class A
//{
//public:
//    A()
//    {
//        Print();
//    }
//
//    void Print()
//    {
//        cout << "Print()" << endl;
//    }
//
//    // private:
//    int _a = 1;
//};
//
//
//int main()
//{
//    A a;
//    return 0;
//}


//// 测试 < , >可不可以比较不同的数据类型
//// 可以
//
//int main()
//{
//	int a = 1;
//	double b = 2.32;
//	a > b;
//	return 0;
//}



//// 测试栈上的地址被free
//// 错误行为
//
//int main()
//{
//	int a = 1;
//	int* p = &a;
//
//	free(p);
//	p = nullptr;
//	return 0;
//}


//// 重载左移运算符时返回值不传引用
//// 报错：
///*
//“std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &)”: 尝试引用已删除的函数
//
//*/
//// 传参时将out写为const ostream&类型时，也会报类似的错误
//
//class Peo
//{
//	// 在哪里写友元函数都没问题，因为他只是一个声明
//	friend ostream& operator<<(ostream& out, const Peo& p);
//
//	void test() const
//	{
//		cout << "test const" << endl;
//	}
//
//	void test() 
//	{
//		cout << "test" << endl;
//	}
//
//private:
//	int _age = 1;
//};
//
//// 不能在类内进行重载，因为this指针永远是第一个参数，参数的位置无法正确
//ostream& operator<<(ostream& out, const Peo& p)
//{
//	out << p._age << endl;
//	p.test();
//	return out;
//}
//
//int main()
//{
//	Peo p;
//	Peo p1;
//	cout << p << p1;
//	return 0;
//}


/*****************2024.7.14**********************/

//// C++new一个数组时，能不能同时初始化
//
//int main()
//{
//	int* p1 = new int[10] {1, 2, 3, 4};
//	// C++11支持，C++98不支持
//	return 0;
//}



//// new自定义类型的数组时，构造函数有多个参数时怎么初始化
//// 必须要有默认构造函数，也就是全缺省、无参 或者 系统自带构造函数
//
//class A
//{
//public:
//	A(int a = 0, int b = 0)
//	{
//		cout << "A()" << endl;
//		_a = a;
//		_b = b;
//	}
//private:
//	int _a;
//	int _b;
//};
//
//class B
//{
//public:
//	B(int b = 0)
//	{
//		cout << "B()" << endl;
//		_b = b;
//	}
//private:
//	int _b;
//};
//
//int main()
//{
//	A* p1 = new A[10]{ {1, 2} };
//	delete[] p1;
//
//	A* p2 = new A[10]{ A(1, 3) };
//	delete[] p2;
//
//	A aa(1, 2);
//	A* p3 = new A[10]{aa};
//	delete[] p3;
//
//	B* p4 = new B[10]{1};
//	delete[] p4;
//
//	return 0;
//}


//// 看try,catch捕捉异常是捕捉try里面的，还是捕捉try，catch里面的
//// 只捕捉try里面的，而且以下代码只有在x86的情况下才会有问题，x64环境下没有问题
///*
//原因：
//内存限制：
//在32位（x86）系统上，进程的虚拟地址空间通常被限制为4GB（尽管实际上可用的更少，因为系统和其他库会占用一部分）。当你尝试分配接近这个限制的内存时，很可能会因为无法找到足够大的连续内存块而失败。
//在64位（x64）系统上，进程的虚拟地址空间要大得多（通常是几TB或更多），因此更容易找到足够大的连续内存块来满足大型分配请求。
//堆的大小和碎片化：
//堆是程序用于动态内存分配的部分。随着程序运行，堆可能会变得碎片化，这意味着可能无法找到足够大的连续内存块，即使总的可用内存量很大。然而，在64位系统上，由于地址空间要大得多，这种碎片化导致的分配失败的可能性要小得多。
//异常类型：
//你的catch块试图捕获std::exception，但new在分配失败时会抛出std::bad_alloc。你应该捕获std::bad_alloc而不是std::exception。
//编译器和运行时库的行为：
//不同的编译器和运行时库可能有不同的内存分配策略和优化，这可能会影响它们如何处理大型内存分配请求。
//操作系统限制：
//操作系统可能会施加额外的限制，例如对单个进程可以使用的最大内存量的限制。这些限制在32位和64位系统上可能不同。
//*/
//
//
//void func()
//{
//	char* p = new char[0x7fffffff];
//	cout << (void*)p << endl;
//}
//
//int main()
//{
//	try
//	{
//		func();
//	}
//	catch(const exception& e)
//	{
//		cout << "In catch" << endl;
//		// func();
//	}
//
//	return 0;
//}


//// 如果写了~A()，使用delete和free都会报错，只有delete[]时才没有问题，
//// 但是没有写~A()时，三个都没有问题
//
//class A
//{
//public:
//	A(int a = 0)
//		:_a1(a)
//	{}
//
//	~A()
//	{
//		cout << "~A()" << endl;
//	}
//
//private:
//	int _a1;
//};
//
//int main()
//{
//	A* p2 = new A[10];
//	// free(p2);// 会崩溃，因为释放的位置不对，没有释放干净
//	free(p2 - 1);// 不会崩溃
//
//	// delete p2; // 会崩溃，因为释放的位置不对，指针前面的四个字节记录了申请了多少个空间，而释放这个位置，没有前移4个字节，导致没有释放干净
//	// delete (p2 - 1); // 不会崩溃，但是只会调用一次析构
//	
//	//delete[] p2; // 正确
//
//	return 0;
//}



//// 调用函数时，汇编代码中call        func(0A1528h)括号中填的地址是什么
///*
//在汇编语言中，call func 的语法表示调用一个函数 func。括号中的地址 0A1528h 表示函数 func 的入口地址。在汇编语言中，函数的入口地址是指函数代码的起始位置，即程序将执行的第一条指令的地址。
//
//具体来说，0A1528h 是一个虚拟内存地址，它指向存储在计算机内存中的函数代码的开始位置。当汇编指令 call func 执行时，计算机会跳转到地址 0A1528h 处开始执行函数 func 的代码。
//
//这个地址通常是编译器在编译时或链接器在链接时决定的，它取决于程序的内存布局和链接方式。
//*/
//
//
//void func()
//{
//
//}
//
//int main()
//{
//
//	func();
//
//	return 0;
//}


//// 检验可不可以重载内置类型的运算符
//// 报错：“operator = ”必须是非静态成员，重载中至少要有一个是自定义类型
//
//int operator=(int b)
//{
//	return 1;
//}
//
//void test1()
//{
//	int b = 0;
//	int a = b;
//	cout << a << endl;
//}


void test12()
{
	string  str = "22222222222222222222222";
	str.resize(4, 'x');
	cout << str << endl;
}

int main()
{
	test12();
	return 0;
}